<!doctype html>



  


<html class="theme-next mist use-motion">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  <link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"/>




  <link href="//fonts.googleapis.com/css?family=Lato:300,400,700,400italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">



<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=0.5.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="nodejs,hexo,源码分析," />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=0.5.0" />






<meta name="description" content="hexo generate 过程分析
brainfuck一下hexo generate的过程: 加载–&amp;gt;渲染–&amp;gt;输出
hexo初始化,加载各种插件读取_config配置读取theme,和配置读取 source 下的.md 和第个md里的开头信息
读取db.json里的信息
用marked 渲染md文件,得到A
用A和theme 加在一起用eje 渲染,得到B
渲染后行B,得到B的各种信">
<meta property="og:type" content="article">
<meta property="og:title" content="hexo_generate_过程分析">
<meta property="og:url" content="http://yoursite.com/2016/03/hexo generate分析/index.html">
<meta property="og:site_name" content="Rainboy">
<meta property="og:description" content="hexo generate 过程分析
brainfuck一下hexo generate的过程: 加载–&amp;gt;渲染–&amp;gt;输出
hexo初始化,加载各种插件读取_config配置读取theme,和配置读取 source 下的.md 和第个md里的开头信息
读取db.json里的信息
用marked 渲染md文件,得到A
用A和theme 加在一起用eje 渲染,得到B
渲染后行B,得到B的各种信">
<meta property="og:updated_time" content="2016-03-18T09:53:40.718Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="hexo_generate_过程分析">
<meta name="twitter:description" content="hexo generate 过程分析
brainfuck一下hexo generate的过程: 加载–&amp;gt;渲染–&amp;gt;输出
hexo初始化,加载各种插件读取_config配置读取theme,和配置读取 source 下的.md 和第个md里的开头信息
读取db.json里的信息
用marked 渲染md文件,得到A
用A和theme 加在一起用eje 渲染,得到B
渲染后行B,得到B的各种信">



<script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Mist',
    sidebar: {"position":"left","display":"hide"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: 0,
      author: 'Author'
    }
  };
</script>

  <title> hexo_generate_过程分析 | Rainboy </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh_Hans">

  










  
  
    
  

  <div class="container one-collumn sidebar-position-left page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">Rainboy</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle"></p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-home fa-fw"></i> <br />
            
            Startseite
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-th fa-fw"></i> <br />
            
            Kategorien
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-archive fa-fw"></i> <br />
            
            Archiv
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-tags fa-fw"></i> <br />
            
            Tags
          </a>
        </li>
      

      
    </ul>
  

  
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                hexo_generate_过程分析
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">Veröffentlicht am</span>
            <time itemprop="dateCreated" datetime="2016-03-17T22:50:09+08:00" content="2016-03-17">
              2016-03-17
            </time>
          </span>

          
            <span class="post-category" >
              &nbsp; | &nbsp;
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">in</span>
              
                <span itemprop="about" itemscope itemtype="https://schema.org/Thing">
                  <a href="/categories/nodejs/" itemprop="url" rel="index">
                    <span itemprop="name">nodejs</span>
                  </a>
                </span>

                
                

              
            </span>
          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2016/03/hexo generate分析/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/03/hexo generate分析/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>hexo generate 过程分析</p>
<p>brainfuck一下hexo generate的过程:<br> 加载–&gt;渲染–&gt;输出</p>
<p>hexo初始化,加载各种插件<br>读取_config配置<br>读取theme,和配置<br>读取 source 下的.md 和第个md里的开头信息</p>
<p>读取db.json里的信息</p>
<p>用marked 渲染md文件,得到A</p>
<p>用A和theme 加在一起用eje 渲染,得到B</p>
<p>渲染后行B,得到B的各种信息</p>
<p>1:path<br>2:分类<br>3:时间<br>4:标题<br>5:tag<br>6:archive</p>
<p>存下唯一的ID到db.json里</p>
<p>根据path generate到public</p>
<h3 id="具体过程"><a href="#具体过程" class="headerlink" title="具体过程"></a>具体过程</h3><p>输入 hexo genenrate</p>
<p>hexo.cmd –&gt; node hexo generate</p>
<p>hexo-cli –&gt;传递参数给hexo,调用hexo</p>
<p>hexo –&gt;init 初始化 加载各种插件</p>
<p>func = console.get(‘generate’)</p>
<p>hexo.call(func) 开始进入generate的过程<br> var c = self.extend.console.get(name);<br>c.call(self, args).then(resolve, reject);</p>
<p>plugins\console</p>
<pre><code>  console.register(&#39;generate&#39;, &#39;Generate static files.&#39;, {
    options: [
      {name: &#39;-d, --deploy&#39;, desc: &#39;Deploy after generated&#39;},
      {name: &#39;-f, --force&#39;, desc: &#39;Force regenerate&#39;},
      {name: &#39;-w, --watch&#39;, desc: &#39;Watch file changes&#39;}
    ]
  }, require(&#39;./generate&#39;));
</code></pre><p>也就是说console 模块下的generate 是plugins\console\generate.js</p>
<p>就是这个函数generateConsole(args)<br>有这几个generateFile, writeFile,deleteFile,firstGenerate 子函数</p>
<p>if (args.w || args.watch) 是不是watch 模式// 这个我们先不管它</p>
<p>这一部分就是开始的代码,this.load 就是hexo里的load</p>
<pre><code>return this.load().then(firstGenerate).then(function() {
    if (args.d || args.deploy) {
      return self.call(&#39;deploy&#39;, args);
    }
  });
</code></pre><h3 id="Hexo-prototype-load"><a href="#Hexo-prototype-load" class="headerlink" title="Hexo.prototype.load"></a>Hexo.prototype.load</h3><p>这个应该是<strong>加载</strong> 资源用的</p>
<p>//加载db.json数据库<br>return loadDatabase(this) </p>
<p>//输出 <strong>开始处理</strong><br>self.log.info(‘Start processing’);</p>
<p>//得到一个数组 source 和theme 处理后的信息<br>return Promise.all([<br>      self.source.process(),<br>      self.theme.process()<br>    ]);</p>
<p>//开始输出<br>return self._generate({cache: true});</p>
<p>分析:我们可以看到过程和我们上面的想法,差不多<br>根据对bluebird的理解,一串chain中没有发生数据传递,只是依次执行而已,应该是把处理后的数据放到了全局变量中</p>
<h3 id="loadDatabase-this"><a href="#loadDatabase-this" class="headerlink" title="loadDatabase(this)"></a>loadDatabase(this)</h3><p>var loadDatabase = require(‘./load_database’);</p>
<p>//不重复加载<br>if (ctx._dbLoaded) return Promise.resolve();</p>
<p>//<br>var db = ctx.database;<br>var path = db.options.path;<br>var log = ctx.log;</p>
<p>//判断db 文件 是否存在<br>fs.exists(path)<br>//运行db.load()<br>return db.load()</p>
<p>//应该存下是db.json的一些数据<br>base = process.cwd(); hexo 的当前路径<br>this.database = new Database({<br>    version: dbVersion, //版本 var dbVersion = 1;<br>    path: pathFn.join(base, ‘db.json’)//路径处理 var pathFn = require(‘path’);<br>  });</p>
<h3 id="分析db-json"><a href="#分析db-json" class="headerlink" title="分析db.json"></a>分析db.json</h3><p>打开hexo blog目录下的db.json 格式化后看一下</p>
<pre><code>{
    &quot;meta&quot;: {
        &quot;version&quot;: 1, 
        &quot;warehouse&quot;: &quot;2.2.0&quot;
    }, 
    &quot;models&quot;: {
        &quot;Asset&quot;: [],  theme 里的source文件信息
        &quot;Cache&quot;: [], 缓存 ,好像都是theme里的文件,存入cache后,不用重复加载
        &quot;Category&quot;: [ ], 
        &quot;Data&quot;: [ ], 
        &quot;Page&quot;: [ ], 
        &quot;Post&quot;: [],  把文章存到这里,title,_content
        slug,published,date,update,comment,layout
        photos
        link
        id,content,more
        &quot;PostAsset&quot;: [ ], 
        &quot;PostCategory&quot;: [ ], 
        &quot;PostTag&quot;: [ ], 
        &quot;Tag&quot;: [ ]
    }
}
</code></pre><p>  var Database = require(‘warehouse’);<br>  db.load</p>
<p>  查了一下npmjs 里的warehouse:Simple JSON-based database 看来是一个仅仅处理<br>  json文件的第三方nodejs 包</p>
<p>  //表明心经加载<br>  ctx._dbLoaded = true;</p>
<h3 id="加载后的数据到哪里去了"><a href="#加载后的数据到哪里去了" class="headerlink" title="加载后的数据到哪里去了?"></a>加载后的数据到哪里去了?</h3><p>我们知道hexo 里<br>this.database = new Database({<br>    version: dbVersion,<br>    path: pathFn.join(base, ‘db.json’)<br>  });</p>
<p>那加载后database 作为一个对象应该存下了db.json里的内存<br>loadDatabase(this) 的作用就是把db.json存在this.database里</p>
<h3 id="开始source-process-和-theme-process"><a href="#开始source-process-和-theme-process" class="headerlink" title="开始source.process 和 theme.process"></a>开始source.process 和 theme.process</h3><p>  this.source = new Source(this);<br>  this.theme = new Theme(this);</p>
<p>我们先看source,本目录下的source.js<br>var Source = require(‘./source’);</p>
<p>打开后看到,调用../box 模块<br>var Box = require(‘../box’);</p>
<p>看一下box的process 函数</p>
<p>可能用到的数据</p>
<pre><code>  this.context = ctx; hexo
  this.base = base; source路径
  this.processors = []; 插件
  this._processingFiles = {};
  this.watcher = null;
  this.Cache = ctx.model(&#39;Cache&#39;);
  this.File = this._createFileClass();
</code></pre><p>过程</p>
<p>1.fs.stat 会返回 path的各种信息<br>看一下hexo.fs的过程<br>graceful-fs 对fs模块的提升<br>是</p>
<p>如果 不是文件夹 就返回</p>
<p>如果不是<br>1.检查不是不是在cache里</p>
<ol>
<li>读取</li>
</ol>
<p>这里有几个问题:<br>1.base: 是ctx.source_dir<br>2.会不会 递归读取?</p>
<p>escapeBackslash \ 全部替换成 /<br>relativeBase 应该是这样 ./source </p>
<p>cacheFiles//???????这个地址真不懂</p>
<p>_readDir—:应该返回的是一个reduce后的数组<br>_readDir真的比较难理解<br>fs.readdir(base) 返回里面的 文件 数组</p>
<p>如果path 是一个文件夹 递归读取</p>
<p>如果是文件 _checkFileStatus<br>Cache.compareFile<br>_checkFileStatus 应该最终返回path代表的文件类型和path的一个{}</p>
<p>self._processFile(file.type,file.path)<br>读取到的每一个文件都 肯定返回一个数据</p>
<hr>
<p>processor.process 处理<br>extend.Processor(),</p>
<p>我们要找到哪个插件注册了processor</p>
<p>内部插件<br>asset.js<br>data.js<br>post.js</p>
<p>process/post.js<br>processPost<br>从db.json里读取post,在这之前已经把post读取到db.json里(doc.insert,不知道有没有渲染 ),</p>
<p>处理了一些信息tag,date,categories</p>
<h3 id="hexo-generate"><a href="#hexo-generate" class="headerlink" title="hexo._generate()"></a>hexo._generate()</h3><p>上面的这么一大部分,完成的操作<br>是把source 和 theme 文件夹是的东西读到db.json里</p>
<p>1.定义了一些属性<br>execFilter before_generate<br>    调用extend.filter<br>execFilter(‘template_locals<br>self.execFilter(‘after_generate</p>
<h3 id="filter"><a href="#filter" class="headerlink" title="filter"></a>filter</h3><p> 内部模块主要在 ./plugins/filter 里</p>
<p> ‘before_generate’, 就是这个文件render_post.js<br> 一个名字就知道是把post[前面我们经load文件到了db.json]渲染了</p>
<p> 核心代码:<br>  return self.post.render(post.full_source, post).then(function() {<br>        return post.save();<br>full_source这个属性????, 这个东西就怎么出现的？</p>
<p>post.save() ????? 难道database 返回的是一个对象?</p>
<p>!!! 一个重要的问题:<br>    前面有可能都理解错了,如果是第一次读取文件genearte,存的db不是存在db.json里<br>    那就要重要去理解 hexo.model 这个函数!!!!!!,很重要</p>
<p>model 不是db.json<br> 要注要这个,看看这个Post 是如果使用的?<br> 是不是直接操作db.json<br> hexo中this.post = new Post(this);</p>
<p>看到这里,知道调用hexo.post模块<br>post.full_source 是 文件路径<br>post 是从modle(‘post’) 里的一个文章<br>self.post.render(post.full_source,post).then(function() {<br>        return post.save();<br>      });</p>
<p>在hexo中this.post = new Post(this);</p>
<p>./render.js中<br>var renderer = self.getRenderer(ext);//得到md<br>ctx.extend.renderer.get<br>    return renderer.call(ctx, data, options);</p>
<p>可以看到这个就是marked<br>hexo.extend.renderer.register(‘md’, ‘html’, renderer, true);<br>调用hexo.render.render()函数 render就是marked 一会验证一下</p>
<h3 id="this-execFilter-‘before-generate’"><a href="#this-execFilter-‘before-generate’" class="headerlink" title="this.execFilter(‘before_generate’"></a>this.execFilter(‘before_generate’</h3><p>所以说这样before_generate 会把md渲染</p>
<h3 id="run-generate"><a href="#run-generate" class="headerlink" title="run generate"></a>run generate</h3><h3 id="self-execFilter-‘template-locals’-locals"><a href="#self-execFilter-‘template-locals’-locals" class="headerlink" title="self.execFilter(‘template_locals’, locals,"></a>self.execFilter(‘template_locals’, locals,</h3><p>!! 渲染了md 文件之后,那就是渲染ejs 主题了<br>return ctx.render.render({<br>      text: data.content,<br>      path: source,<br>      engine: data.engine,<br>      toString: true,<br>      onRenderEnd: tagFilter<br>    }, options);</p>
<p>tag.渲染<br>tag.render(data.content, data);</p>
<p>让我看到ejs 渲染:</p>
<p>post.save() 完成渲染 保存</p>
<p>var theme = this.theme;<br>view = theme.getView(name)<br>view.render(locals).then(saveCache);</p>
<p>render = _render = hexo.render</p>
<p>这里的view难以理解,</p>
<p>只要证明hexo.render里有 调用了<br>ctx.extend.renderer;</p>
<p>累了!!</p>
<p>hexo的工作模式 是插件之间的协作,应该理解hexo的插件工作</p>
<h3 id="generator-生成tag-archive-等"><a href="#generator-生成tag-archive-等" class="headerlink" title="generator  生成tag archive 等"></a>generator  生成tag archive 等</h3><h3 id="name-layout-i"><a href="#name-layout-i" class="headerlink" title="name = layout[i];"></a>name = layout[i];</h3><pre><code>      view = theme.getView(name);
</code></pre><p>证明这一句调用了ejs<br>return view.render(locals).then(saveCache);</p>
<p>load 之后都存的cache里面</p>
<p>view.render 应该会把这存到db.cache</p>

      
    </div>

    <div>
      
        
      
    </div>

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/nodejs/" rel="tag">#nodejs</a>
          
            <a href="/tags/hexo/" rel="tag">#hexo</a>
          
            <a href="/tags/源码分析/" rel="tag">#源码分析</a>
          
        </div>
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/03/mongoose/" rel="next" title="mongoose 学习笔记">
                <i class="fa fa-chevron-left"></i> mongoose 学习笔记
              </a>
            
          </div>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/03/STL-vector/" rel="prev" title="STL 学习讲解一">
                STL 学习讲解一 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div class="ds-thread" data-thread-key="2016/03/hexo generate分析/"
           data-title="hexo_generate_过程分析" data-url="http://yoursite.com/2016/03/hexo generate分析/">
      </div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            Inhaltsverzeichnis
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            Übersicht
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel ">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.jpg"
               alt="Rainboy" />
          <p class="site-author-name" itemprop="name">Rainboy</p>
          <p class="site-description motion-element" itemprop="description">Rainboy Personal Blog by Hexo</p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">16</span>
              <span class="site-state-item-name">Artikel</span>
            </a>
          </div>

          
            <div class="site-state-item site-state-categories">
              <a href="/categories">
                <span class="site-state-item-count">10</span>
                <span class="site-state-item-name">Kategorien</span>
              </a>
            </div>
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">23</span>
                <span class="site-state-item-name">Tags</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
        </div>

        
        

        
        <div class="links-of-blogroll motion-element">
          
        </div>

      </section>

      
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc-indicator-top post-toc-indicator">
            <i class="fa fa-angle-double-up"></i>
          </div>
          <div class="post-toc">
            
              
            
            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#具体过程"><span class="nav-number">1.</span> <span class="nav-text">具体过程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Hexo-prototype-load"><span class="nav-number">2.</span> <span class="nav-text">Hexo.prototype.load</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#loadDatabase-this"><span class="nav-number">3.</span> <span class="nav-text">loadDatabase(this)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#分析db-json"><span class="nav-number">4.</span> <span class="nav-text">分析db.json</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#加载后的数据到哪里去了"><span class="nav-number">5.</span> <span class="nav-text">加载后的数据到哪里去了?</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#开始source-process-和-theme-process"><span class="nav-number">6.</span> <span class="nav-text">开始source.process 和 theme.process</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#hexo-generate"><span class="nav-number">7.</span> <span class="nav-text">hexo._generate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#filter"><span class="nav-number">8.</span> <span class="nav-text">filter</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#this-execFilter-‘before-generate’"><span class="nav-number">9.</span> <span class="nav-text">this.execFilter(‘before_generate’</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#run-generate"><span class="nav-number">10.</span> <span class="nav-text">run generate</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#self-execFilter-‘template-locals’-locals"><span class="nav-number">11.</span> <span class="nav-text">self.execFilter(‘template_locals’, locals,</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#generator-生成tag-archive-等"><span class="nav-number">12.</span> <span class="nav-text">generator  生成tag archive 等</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#name-layout-i"><span class="nav-number">13.</span> <span class="nav-text">name = layout[i];</span></a></li></ol></div>
            
          </div>
          <div class="post-toc-indicator-bottom post-toc-indicator">
            <i class="fa fa-angle-double-down"></i>
          </div>
        </section>
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2016</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Rainboy</span>
</div>

<div class="powered-by">
  Erstellt mit  <a class="theme-link" href="http://hexo.io">Hexo</a>
</div>

<div class="theme-info">
  Theme -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Mist
  </a>
</div>



      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  


  




<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


  <script type="text/javascript" src="/vendors/jquery/index.js?v=2.1.3"></script>

  <script type="text/javascript" src="/vendors/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  <script type="text/javascript" src="/vendors/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  <script type="text/javascript" src="/vendors/velocity/velocity.min.js"></script>

  <script type="text/javascript" src="/vendors/velocity/velocity.ui.min.js"></script>

  <script type="text/javascript" src="/vendors/fancybox/source/jquery.fancybox.pack.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=0.5.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=0.5.0"></script>



  
  

  
  
<script type="text/javascript" src="/js/src/scrollspy.js?v=0.5.0"></script>

<script type="text/javascript" id="sidebar.toc.highlight">
  $(document).ready(function () {
    var tocSelector = '.post-toc';
    var $tocSelector = $(tocSelector);
    var activeCurrentSelector = '.active-current';

    $tocSelector
      .on('activate.bs.scrollspy', function () {
        var $currentActiveElement = $(tocSelector + ' .active').last();

        removeCurrentActiveClass();
        $currentActiveElement.addClass('active-current');

        $tocSelector[0].scrollTop = $currentActiveElement.position().top;
      })
      .on('clear.bs.scrollspy', function () {
        removeCurrentActiveClass();
      });

    function removeCurrentActiveClass () {
      $(tocSelector + ' ' + activeCurrentSelector)
        .removeClass(activeCurrentSelector.substring(1));
    }

    function processTOC () {
      getTOCMaxHeight();
      toggleTOCOverflowIndicators();
    }

    function getTOCMaxHeight () {
      var height = $('.sidebar').height() -
                   $tocSelector.position().top -
                   $('.post-toc-indicator-bottom').height();

      $tocSelector.css('height', height);

      return height;
    }

    function toggleTOCOverflowIndicators () {
      tocOverflowIndicator(
        '.post-toc-indicator-top',
        $tocSelector.scrollTop() > 0 ? 'show' : 'hide'
      );

      tocOverflowIndicator(
        '.post-toc-indicator-bottom',
        $tocSelector.scrollTop() >= $tocSelector.find('ol').height() - $tocSelector.height() ? 'hide' : 'show'
      )
    }

    $(document).on('sidebar.motion.complete', function () {
      processTOC();
    });

    $('body').scrollspy({ target: tocSelector });
    $(window).on('resize', function () {
      if ( $('.sidebar').hasClass('sidebar-active') ) {
        processTOC();
      }
    });

    onScroll($tocSelector);

    function onScroll (element) {
      element.on('mousewheel DOMMouseScroll', function (event) {
          var oe = event.originalEvent;
          var delta = oe.wheelDelta || -oe.detail;

          this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
          event.preventDefault();

          toggleTOCOverflowIndicators();
      });
    }

    function tocOverflowIndicator (indicator, action) {
      var $indicator = $(indicator);
      var opacity = action === 'show' ? 1 : 0;
      $indicator.velocity ?
        $indicator.velocity('stop').velocity({
          opacity: opacity
        }, { duration: 100 }) :
        $indicator.stop().animate({
          opacity: opacity
        }, 100);
    }

  });
</script>

<script type="text/javascript" id="sidebar.nav">
  $(document).ready(function () {
    var html = $('html');
    var TAB_ANIMATE_DURATION = 200;
    var hasVelocity = $.isFunction(html.velocity);

    $('.sidebar-nav li').on('click', function () {
      var item = $(this);
      var activeTabClassName = 'sidebar-nav-active';
      var activePanelClassName = 'sidebar-panel-active';
      if (item.hasClass(activeTabClassName)) {
        return;
      }

      var currentTarget = $('.' + activePanelClassName);
      var target = $('.' + item.data('target'));

      hasVelocity ?
        currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function () {
          target
            .velocity('stop')
            .velocity('transition.slideDownIn', TAB_ANIMATE_DURATION)
            .addClass(activePanelClassName);
        }) :
        currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function () {
          currentTarget.hide();
          target
            .stop()
            .css({'opacity': 0, 'display': 'block'})
            .animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function () {
              currentTarget.removeClass(activePanelClassName);
              target.addClass(activePanelClassName);
            });
        });

      item.siblings().removeClass(activeTabClassName);
      item.addClass(activeTabClassName);
    });

    $('.post-toc a').on('click', function (e) {
      e.preventDefault();
      var targetSelector = NexT.utils.escapeSelector(this.getAttribute('href'));
      var offset = $(targetSelector).offset().top;
      hasVelocity ?
        html.velocity('stop').velocity('scroll', {
          offset: offset  + 'px',
          mobileHA: false
        }) :
        $('html, body').stop().animate({
          scrollTop: offset
        }, 500);
    });

    // Expand sidebar on post detail page by default, when post has a toc.
    NexT.motion.middleWares.sidebar = function () {
      var $tocContent = $('.post-toc-content');

      if (CONFIG.sidebar.display === 'post' || CONFIG.sidebar.display === 'always') {
        if ($tocContent.length > 0 && $tocContent.html().trim().length > 0) {
          NexT.utils.displaySidebar();
        }
      }
    };
  });
</script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=0.5.0"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"rainboy"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
  





  
  
  
  <script type="text/x-mathjax-config">
    MathJax.Hub.Config({
      tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
      }
    });
  </script>

  <script type="text/x-mathjax-config">
    MathJax.Hub.Queue(function() {
      var all = MathJax.Hub.getAllJax(), i;
      for (i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';
      }
    });
  </script>

  
    <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  


  

  

</body>
</html>
